package com.bj58.mis.apm.server.logreceiver.service.impl;

import com.bj58.mis.apm.server.core.common.result.Page;
import com.bj58.mis.apm.server.core.common.result.SimplePage;
import com.bj58.mis.apm.server.core.receiver.BaseCollectLog;
import com.bj58.mis.apm.server.core.receiver.LogReceiver;
import com.bj58.mis.apm.server.core.util.JsonUtil;
import com.bj58.mis.apm.server.logreceiver.config.LogReceiversConfig;
import com.bj58.mis.apm.server.logreceiver.dto.ApmLog;
import com.bj58.mis.apm.server.logreceiver.dto.ApmLogResultType;
import com.bj58.mis.apm.server.logreceiver.query.ApmlogQuery;
import com.bj58.mis.apm.server.logreceiver.query.PageInfo;
import com.bj58.mis.apm.server.logreceiver.repository.ApmLogRepository;
import com.bj58.mis.apm.server.logreceiver.service.ApmLogService;
import com.bj58.mis.apm.server.logreceiver.vo.ApmLogVO;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Service;

import java.io.UnsupportedEncodingException;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @author: zhangfx
 * @create: 2018-06-06 17:42
 **/
@Service
public class ApmLogServiceImpl implements ApmLogService, InitializingBean, ApplicationContextAware{
    private Logger logger = LoggerFactory.getLogger(this.getClass());

    private ApplicationContext ac;

    @Autowired
    private LogReceiversConfig logReceiversConfig;

    @Autowired
    private ApmLogRepository repository;

    private Map<String, Class> logModelClassMap = new HashMap<>();

    private Map<String, LogReceiver> logReceiverServiceMap = new HashMap<>();

    @Override
    public void save(ApmLog apmLog) {

        apmLog.setReceiveTime(new Date());
        try {
            apmLog.setDataSize(apmLog.getLogData().getBytes("utf-8").length);
        }catch (UnsupportedEncodingException e){
            throw new RuntimeException(e);
        }

        String collectType = apmLog.getType();

        Class logModelClass = logModelClassMap.get(collectType);
        LogReceiver logReceiver = logReceiverServiceMap.get(collectType);
        if(logModelClass==null || logReceiver==null){
            logger.warn("不支持的日志类型，type={}, apmLog={}", collectType, apmLog);
            apmLog.setResult(ApmLogResultType.NOLOGTYPE);
        }else {
            try {
                BaseCollectLog collectLog = (BaseCollectLog) JsonUtil.fromJson(apmLog.getLogData(), logModelClassMap.get(collectType));
                collectLog.setAppName(apmLog.getAppName());
                collectLog.setHostName(apmLog.getHostName());
                logReceiver.receive(collectLog);
                apmLog.setResult(ApmLogResultType.DEALSUCCESS);
                apmLog.setDealTime(new Date());
            }catch(Exception e){
                apmLog.setResult(ApmLogResultType.DEALFAULT);
                throw new RuntimeException(e);
            }
        }

        repository.save(apmLog);
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        Map<String, Map<String ,String>> receivers = logReceiversConfig.getReceivers();
        for(String type : receivers.keySet()){
            logModelClassMap.put(type, Class.forName(receivers.get(type).get("model")));

            String receiverServiceName = receivers.get(type).get("service");
            logReceiverServiceMap.put(type, (LogReceiver)ac.getBean(Class.forName(receiverServiceName)));
        }
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.ac = applicationContext;
    }

    @Override
    public Page<ApmLogVO> queryPage(ApmlogQuery apmlogQuery, PageInfo pageInfo) {
        int page = pageInfo.getPage();
        int limit = pageInfo.getLimit();
        int start = (page - 1) * limit;
        long total = repository.queryCount();
        List<ApmLogVO> records = repository.queryByPage(start, limit).stream().map(log -> getApmLogVO(log)).collect(Collectors.toList());
        return new SimplePage(total, records, page, limit);
    }

    private ApmLogVO getApmLogVO(ApmLog log){
        ApmLogVO vo = new ApmLogVO();
        BeanUtils.copyProperties(log, vo);
        return vo;
    }
}
